package com.zyj.benchmark.sample;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.*;

/**
 * @Setup , @TearDown 这两个注解可以写在多个方法上
 */

@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class Sample_07_FixtureLevelInvocation {

    /*
     * This state handles the executor.
     * Note we create and shutdown executor with Level.Trial, so
     * it is kept around the same across all iterations.
     */
    @State(Scope.Benchmark) //全局公用这个实例
    public static class NormalState {
        ExecutorService service;

        @Setup(Level.Trial) //全局只执行一次
        public void up() {
            service = Executors.newCachedThreadPool();
        }

        @TearDown(Level.Trial) //全局只执行一次
        public void down() {
            service.shutdown();
        }

    }


    /*
     * This is the *extension* of the basic state, which also
     * has the Level.Invocation fixture method, sleeping for some time.
     */

    public static class LaggingState extends NormalState {
        public static final int SLEEP_TIME = Integer.getInteger("sleepTime", 10);

        @Setup(Level.Invocation) //每次调用都会被执行
        public void lag() throws InterruptedException {
            TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
        }
    }

    /*
     * This allows us to formulate the task: measure the task turnaround in
     * "hot" mode when we are not sleeping between the submits, and "cold" mode,
     * when we are sleeping.
     */
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    public double measureHot(
            NormalState e, //使用正常的线程池
            final Scratch s
    ) throws ExecutionException, InterruptedException {
        return e.service.submit(new Task(s)).get();
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    public double measureCold(
            LaggingState e,//每次调用之前会等待10ms
            final Scratch s
    ) throws ExecutionException, InterruptedException {
        return e.service.submit(new Task(s)).get();
    }


    @State(Scope.Thread) //每个线程都会用各自的实例
    public static class Scratch {
        private double p;

        public double doWork() {
            p = Math.log(p);
            return p;
        }
    }

    public static class Task implements Callable<Double> {
        private Scratch s;

        public Task(Scratch s) {
            this.s = s;
        }

        @Override
        public Double call() {
            return s.doWork();
        }
    }

    /*
     * You can see the cold scenario is running longer, because we pay for
     * thread wakeups.
     */
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(Sample_07_FixtureLevelInvocation.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }

}
